/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package io.iec.edp.caf.commons.runtime.msu;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import io.iec.edp.caf.commons.runtime.msu.entities.MsuCommonInfo;
import io.iec.edp.caf.commons.runtime.msu.entities.ServiceUnitYaml;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

/**
 * msu配置读取工具类
 * 包含了一些序列化等操作
 * todo 工具类解耦后考虑使用序列化工具
 */
public class MsuConfigReader {

    //序列化工具
    private static ObjectMapper objectMapper = new ObjectMapper();

    private static Log log = LogFactory.getLog(MsuConfigReader.class);

    static public MsuCommonInfo analysisMsuInfo(String jsonString) {
        MsuCommonInfo result = new MsuCommonInfo();
        try {
            String jsonStrTmp = jsonString.substring(jsonString.indexOf(":") + 1, jsonString.lastIndexOf("}"));
            if (jsonStrTmp.length() == 0) {
                throw new RuntimeException("A ServiceUnit.json has no content.");
            }
            result = objectMapper.readValue(jsonStrTmp, MsuCommonInfo.class);
        } catch (Throwable e) {
            log.error("Get Su from ServiceUnit.json error, content is: "
                    + jsonString + " failed reason: " + e.getMessage());
        }
        return result;
    }

    static public ServiceUnitYaml analysisMsuYamlInfo(Map<String, Object> yamlContent) {
        ServiceUnitYaml result = new ServiceUnitYaml();
        try {
            result = objectMapper.readValue(objectMapper.writeValueAsString(yamlContent), ServiceUnitYaml.class);
        } catch (Throwable e) {
            log.error("Get Su from service-unit.yaml error, content is: "
                    + yamlContent + " failed reason: " + e.getMessage());
        }
        return result;
    }

    /**
     * @param content caf_serviceunit.json文件内容
     * @param allSu   环境中所有su(包括未启用的)
     */
    static public List<String> getEnableSuListFromJson(String content, List<String> allSu) {
        List<String> enableSuList = new ArrayList<>();
        //没有su信息则为空
        if (allSu == null) return enableSuList;

        //json配置是否为黑白名单
        boolean isBlackList = true;
        if (content == null || "".equals(content)) {
            log.error("Caf_ServiceUnit.json has no content");
            return new ArrayList<>();
        }
        try {
            //caf_serviceunit.json中的su信息列表
            List<Map<String, Object>> suList = new ArrayList<>();
            //序列化文件
            Map<String, Object> deployConfig = objectMapper.readValue(content, Map.class);
            if (deployConfig == null) {
                throw new RuntimeException("Can't read Caf_ServiceUnit.json");
            }
            //获取配置类对象
            Map<String, Object> deploymentConfiguration = (Map) deployConfig.get(MsuConfigVariable.CAF_JSON);

            if (deploymentConfiguration.containsKey(MsuConfigVariable.CAF_JSON_STRATEGY)) {
                isBlackList = !deploymentConfiguration.get(MsuConfigVariable.CAF_JSON_STRATEGY).toString().equalsIgnoreCase("WhiteList");
            }
            //获取su信息列表
            if (deploymentConfiguration.containsKey(MsuConfigVariable.CAF_JSON_SU))
                suList = (List) deploymentConfiguration.get(MsuConfigVariable.CAF_JSON_SU);

            //获取启用列表和禁用列表
            List<String> disableSu = new ArrayList<>();
            List<String> ableSu = new ArrayList<>();

            //全部转成小写
            suList.forEach(su -> {
                if (su.containsKey(MsuConfigVariable.CAF_JSON_SU_NAME) && su.containsKey(MsuConfigVariable.CAF_JSON_SU_ENABLE))
                    if ((boolean) su.get(MsuConfigVariable.CAF_JSON_SU_ENABLE)) {
                        ableSu.add(su.get(MsuConfigVariable.CAF_JSON_SU_NAME).toString());
                    } else {
                        disableSu.add(su.get(MsuConfigVariable.CAF_JSON_SU_NAME).toString());
                    }
            });
            if (isBlackList) {
                //黑名单则将su信息列表中的被禁用的su，从全部列表中去除
                allSu.forEach(su -> {
                    boolean addAble = true;
                    for (String yamlSu : disableSu) {
                        if (yamlSu.equalsIgnoreCase(su)) {
                            addAble = false;
                            break;
                        }
                    }
                    if (addAble && !enableSuList.contains(su) && su != null) enableSuList.add(su);
                });
            } else {
                //白名单则只将全部su中包含白名单的加入
                allSu.forEach(su -> {
                    boolean addAble = false;
                    for (String yamlSu : ableSu) {
                        if (yamlSu.equalsIgnoreCase(su)) {
                            addAble = true;
                            break;
                        }
                    }
                    if (addAble && !enableSuList.contains(su) && su != null) enableSuList.add(su);
                });
            }
        } catch (Exception e) {
            log.error("Get info from Caf_ServiceUnit.json error,error reason: " + e.getMessage()
                    + " Caf_ServiceUnit.json info :\n" + content);
        } finally {
            return enableSuList;
        }
    }

    static public List<String> getEnableSuListFromYaml(Map<String, Object> yamlContent, List<String> allSu) {
        List<String> enableSus = new ArrayList<>();
        //没有su信息则为空
        if (allSu == null) return enableSus;

        //yaml配置是否为黑白名单
        boolean isBlackList = true;

        //如果yaml中有配置
        try {
            if (yamlContent.containsKey(MsuConfigVariable.CAF_YAML)) {
                Map config = (Map) yamlContent.get(MsuConfigVariable.CAF_YAML);
                String yamlSuString = "";
                if (config != null) {
                    if (config.containsKey(MsuConfigVariable.CAF_YAML_STRATEGY))
                        isBlackList = (!"whitelist".equalsIgnoreCase((String) config.get(MsuConfigVariable.CAF_YAML_STRATEGY)));
                    if (config.containsKey(MsuConfigVariable.CAF_YAML_SU))
                        yamlSuString = (String) config.get(MsuConfigVariable.CAF_YAML_SU);
                }
                if (yamlSuString == null) yamlSuString = "";
                //按,分割
                List<String> yamlSuList = Arrays.asList(yamlSuString.split(","));

                if (isBlackList) {
                    //黑名单被禁用的su，从全部列表中去除
                    allSu.forEach(su -> {
                        boolean addAble = true;
                        for (String yamlSu : yamlSuList) {
                            yamlSu = yamlSu.trim();
                            if (yamlSu.equalsIgnoreCase(su)) {
                                addAble = false;
                                break;
                            }
                        }
                        if (addAble && !enableSus.contains(su) && su != null) enableSus.add(su);
                    });
                } else {
                    //白名单则验证是否在全部列表中
                    allSu.forEach(su -> {
                        boolean addAble = false;
                        for (String yamlSu : yamlSuList) {
                            yamlSu = yamlSu.trim();
                            if (yamlSu.equalsIgnoreCase(su)) {
                                addAble = true;
                                break;
                            }
                        }
                        if (addAble && !enableSus.contains(su) && su != null) enableSus.add(su);
                    });
                }
            } else {
                return null;
            }
        } catch (Throwable e) {
            log.error("Get msu info error from application.yaml, content is: " + yamlContent, e);
        }
        return enableSus;
    }

    static {
        //对象的所有字段全部列入
        objectMapper.setSerializationInclusion(JsonInclude.Include.ALWAYS);
        //取消默认转换timestamps形式
        objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
        //忽略空Bean转json的错误
        objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
        //所有的日期格式都统一为以下的样式，即yyyy-MM-dd HH:mm:ss
//        objectMapper.setDateFormat(new SimpleDateFormat(STANDARD_FORMAT));
        //忽略 在json字符串中存在，但是在java对象中不存在对应属性的情况。防止错误
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        //设置可用单引号
        objectMapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
        //设置字段可以不用双引号包括
        objectMapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);

        //https://blog.csdn.net/qfzhangwei/article/details/85009163
        objectMapper.configure(JsonGenerator.Feature.IGNORE_UNKNOWN, true);
        objectMapper.configure(JsonGenerator.Feature.WRITE_BIGDECIMAL_AS_PLAIN, true);
        //允许缺少数据
        objectMapper.configure(JsonParser.Feature.ALLOW_MISSING_VALUES, true);
        //大小写脱敏 默认为false  需要改为true
        objectMapper.configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES, true);
        //OffsetTimeDate保留时区
        objectMapper.disable(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE);
    }
}
